<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/**
 * CFD 脚本
 */
class Cron_CFD extends CI_Controller {
	private $redis;
	private $cfdClass;
	private $cfdConfig;
	private $db;
	private $log_db;
	private $logFile;
	private $symbol;
	public function __construct(){  
        parent::__construct();
        $this->load->config('cfd');
        if(!is_cli()){
        	header("HTTP/1.0 404 Not Found");
        	show_error('Not Found',404);
        	die;
        }
        //加载CFD操作类
		$this->load->library('cfdClass');
		$this->cfdClass = $this->cfdclass;
    }

    /**
     * CFD队列1，主要处理开仓、平仓、追加、爆仓、止损等功能
     * @return [type] [description]
     */
	public function queue($symbol){

		
		$this->symbol = $symbol;
		//log文件名
		$this->logFile = $symbol."_queue";
		// 平滑重启
		$stop = '/tmp/log/'.$this->logFile.'.stop';
		//加载CFD操作类
		if(!$this->cfdClass->setProduct($symbol,'IB')){//设置产品
			jsonReturn(-1,"无效操作[10001]！");//无效的操作
		}
		$this->cfdConfig = $this->cfdClass->getCfdConfig();

		$queue1Key = $this->cfdConfig['common']['queue1']."_".$symbol;
		$queue2Key = $this->cfdConfig['common']['queue2']."_".$symbol;

		writeDebug('['.date('Y-m-d H:i:s').'] ['.$symbol.'] supervistor重启', 2, 'Crond_CFD_queue');

		$this->redis = $this->cfdClass->getRedis();
		$this->updateCommission();
		while(true){
			if (file_exists($stop)) {
		        writeDebug('['.$datetime.'] 自杀性重启中', $this->logFile);
		        break;
		        die();
		    }
		    
		    $datetime = date('Y-m-d H:i:s');
		    
		    $queue = $this->redis->rPop($queue2Key);
		    if($queue == false){
		    	$queue = $this->redis->rPop($queue1Key);
		    }
		    // $queue = 'bid|cny|24';
		    if($queue == false) {
		    	// 睡 0.5 秒
				usleep(500000);
				// 跳出本循环
				continue;
		    }
		    //防止MySQL server has gone away
		    $this->db = $this->load->database('default',true);
			$this->log_db = $this->load->database('log',true);

			$this->cfdClass->setDb($this->db);
			$this->cfdClass->setLogDb($this->log_db);
		    echo "[$datetime] $queue\n";
		    // 队列处理
			$queueArr = explode('|', $queue);
			$actionType = $queueArr[0];
			if(in_array($actionType, array('bid','ask','bid_ping','ask_ping','cancel','setStop','check_ask','check_bid','stop_ask','stop_bid'))){
				list($actionType, $dtype, $id) = explode('|', $queue);
				if(!$this->cfdClass->setDenom($dtype)){//设置计价方式
					writeDebug('['.$datetime.'] 设置计价方式失败！:'.$queue, $this->logFile);
					continue;
				}
			}else if(in_array($actionType, array('bao_ask','bao_bid'))){
				$actionType = $queue;
			}
			writeDebug('['.$datetime.'] 开始执行:'.$queue, $this->logFile);
			// 分类处理
			switch ($actionType) {
				case 'bid': // 开仓买多
				case 'ask': // 开仓卖空
					// 检查交易时间
					if ($this->cfdClass->checkTime() && $this->checkAbnormal($actionType)) {
						// 查询订单信息
						$table = "cfd_cfd_".$actionType;
						$where = array('id'=>$id);
						$query = $this->db->select()->from($table)->where($where)->limit(1)->get();
						if ($query->row()) {
							$orderData = $query->row_array();
							if($orderData['flag']!=0 && $orderData['status']!=0) writeDebug('['.$datetime.'] 订单状态不正确: '.$queue, $this->logFile);
							if($orderData['kp']!='open') writeDebug('['.$datetime.'] 订单方向不正确: '.$queue, $this->logFile);
							// 分类处理
							$orderData['type'] === '0' ? $this->marketPrice($actionType, $orderData) : $this->fixedPrice($actionType, $orderData);
						}else{
							writeDebug('['.$datetime.'] 订单不存在: '.$queue, $this->logFile);	
						}
					} else {
						writeDebug('['.$datetime.'] 不在交易时间内!: '.$queue, $this->logFile);
						$this->cancel($actionType, $id, 1);
					}
					break;
				case 'bid_ping': // 买多平仓
				case 'ask_ping': // 卖空平仓
					list($actionType) = explode('_', $actionType);
					if ($this->cfdClass->checkTime() && $this->checkAbnormal($actionType)) {
						// 查询订单信息
						$table = "cfd_cfd_".$actionType;
						$where = array('id'=>$id);
						$query = $this->db->select()->from($table)->where($where)->limit(1)->get();
						if ($query->row()) {
							$orderData = $query->row_array();
							if($orderData['flag']!=0 && $orderData['status']!=0) writeDebug('['.$datetime.'] 订单状态不正确: '.$queue, $this->logFile);
							if($orderData['kp']!='close') writeDebug('['.$datetime.'] 订单方向不正确: '.$queue, $this->logFile);
							// 分类处理
							$orderData['type'] === '0' ? $this->marketPricePing($actionType, $orderData) : $this->fixedPricePing($actionType, $orderData);
						}else{
							writeDebug('['.$datetime.'] 订单不存在: '.$queue, $this->logFile);	
						}
					} else {
						writeDebug('['.$datetime.'] 不在交易时间内!: '.$queue, $this->logFile);
						$this->cancel($actionType, $id, 1);
						//止损平仓挂单出错，需要把止损状态改成-1
						// $this->resetStopLose($queue);
					}
					break;
				case 'cancel': // 挂单撤单
					list($actionType, $bs, $id) = explode('|', $queue);
					$this->cancel($bs, $id);
					break;
				case 'setStop': // 设置止损
					if ($this->cfdClass->checkTime() && $this->checkAbnormal()) {
						list($actionType, $price, $id, $status) = explode('|', $queue);
						$this->setStopLose($id, $price, $status);
					}
					break;
				case 'check_hedge': // 检查并对冲
					$this->processHedge($id);
					break;
				case 'index': // 检查对冲系数
					$this->updateHedgeIndex();
					break;
				case 'check_ask':
				case 'check_bid':
					if ($this->cfdClass->checkTime() && $this->checkAbnormal()) {
						list($actionType, $val) = explode('_', $actionType);
						$this->checkGua($val, $datetime);	
					}
					break;
				case 'bao_ask':
				case 'bao_bid':
					if ($this->checkAbnormal()) {
						list($actionType, $val) = explode('_', $actionType);
						$this->checkBao($val, $datetime);	
					}
					break;
				case 'stop_ask':
				case 'stop_bid':
					if ($this->cfdClass->checkTime() && $this->checkAbnormal()) {
						list($actionType, $val) = explode('_', $actionType);
						$this->checkStoplose($val, $datetime);
					}
					break;
				default:
					writeDebug('['.$datetime.'] 无法识别的队列: '.$queue, $this->logFile);
			}

		}
	}

	/**
	 * 价格监控
	 * @return [type] [description]
	 */
	public function subscribe_queue($symbol){
		$this->symbol = $symbol;
		//log文件名
		$this->logFile = $symbol."_subscribe_queue";
		// 平滑重启
		$stop = '/tmp/log/'.$this->logFile.'.stop';
		//加载CFD操作类
		if(!$this->cfdClass->setProduct($symbol,'IB')){//设置产品
			jsonReturn(-1,"无效操作[10001]！");//无效的操作
		}
		$this->cfdConfig = $this->cfdClass->getCfdConfig();
		
		// 设置全局变量
		$last_bid  = 0;
		$last_ask  = 0;
		while(true){
			if (file_exists($stop)) {
		        writeDebug('['.$datetime.'] 自杀性重启中', $this->logFile);
		        break;
		        die();
		    }
		    $datetime = date('Y-m-d H:i:s');
		    if($this->cfdClass->checkTime()) {
		    	$data = $this->cfdClass->redisAllData();
				if(empty($data['trade'])){
					usleep(500000);
					continue;
				}
				if($data['trade']['BID_PRICE']<=0 || $data['trade']['ASK_PRICE']<=0){
					usleep(500000);
					continue;
				}
				if($data['trade']['BID_PRICE']>=$data['trade']['ASK_PRICE']){
					usleep(500000);
					continue;
				}
				$arr = array();
				$arr['bid_price'] = $data['trade']['LAST_PRICE'];
				$arr['ask_price'] = $data['trade']['LAST_PRICE'];
				$arr['check_bid'] = bccomp($last_bid, $arr['bid_price'], 6) === 0 ? false : true;
				$arr['check_ask'] = bccomp($last_ask, $arr['ask_price'], 6) === 0 ? false : true;
				$last_bid = $arr['bid_price'];
				$last_ask = $arr['ask_price'];
				// $lastest_price    = $data['trade']['LAST_PRICE'];
				// 检查挂单是否会成交
				// checkDeal($arr);
				// 检查是否会有爆仓
				$this->checkFirstBao($symbol, $arr);
				// 检查是否会有止损/止盈
				// checkStoplose($arr);
				// 睡0.5秒
				usleep(500000);
		    }else{
		    	sleep(1);
		    }
		}
	}

	//结算
	public function settlement($symbol){
		$datetime = date('Y-m-d H:i:s');
		$this->symbol = $symbol;
		//log文件名
		$this->logFile = $symbol."_settlement";
		// 平滑重启
		//加载CFD操作类
		if(!$this->cfdClass->setProduct($symbol,'IB')){//设置产品
			jsonReturn(-1,"无效操作[10001]！");//无效的操作
		}
		$productData = $this->cfdClass->getProductData();
		$settlementArr = explode(',',$productData['settlement']);
		$dst = $this->cfdClass->checkDST($symbol);
		$cur_H = date('H');
		$settlement_H = date('H',strtotime($settlementArr[$dst]));
		if($settlement_H!=$cur_H){
			writeDebug('['.$datetime.'] 不在结算时间!', $this->logFile);
			die($settlement_H."!=".$cur_H."不在结算时间");
		}
		//防止MySQL server has gone away
	    $this->db = $this->load->database('default',true);
		$this->log_db = $this->load->database('log',true);
		$this->cfdConfig = $this->cfdClass->getCfdConfig();
		$rs = array();
		//查询所有挂单
		$bidTB = 'cfd_cfd_bid';
		$where = array('flag'=>0,'status'=>3,'name'=>$symbol);
		$query = $this->db->select()->from($bidTB)->where($where)->get();
		$tmp = $query->result_array();
		$rs['bid'] = empty($tmp) ?  array() : $tmp;

		$askTB = 'cfd_cfd_ask';
		$where = array('flag'=>0,'status'=>3,'name'=>$symbol);
		$query = $this->db->select()->from($askTB)->where($where)->get();
		$tmp = $query->result_array();
		$rs['ask'] = empty($tmp) ?  array() : $tmp;

		foreach ($rs as $actionType => $records) {
			if (!empty($records)) {
				writeDebug('['.$datetime.'] '.$actionType.'自动撤单开始!', $this->logFile);
				foreach ($records as $record) {
					$this->cancel($actionType, $record['id']);
				}
				writeDebug('['.$datetime.'] '.$actionType.'自动撤单结束!', $this->logFile);
			}
		}
		//结算-自动平仓
		$positionTB = 'cfd_cfd_position';
		$where = array('flag'=>0,'name'=>$symbol);
		$query = $this->db->select()->from($positionTB)->where($where)->get();
		$chiArr = $query->result_array();
		$redisData = $this->cfdClass->redisAllData();
		$cjPrice = $redisData['trade']['LAST_PRICE'];
		echo "结算价：".$cjPrice."\n";
		if($cjPrice<=0){
			writeDebug('['.$datetime.'] cjPrice错误:'.$cjPrice, $this->logFile);
			die;
		}
		if(!empty($chiArr)) foreach($chiArr as $record){
			try {
				$this->db->trans_start();//开始事务
				$this->log_db->trans_start();//开始事务

				$id = $record['id'];
				$dtype = $record['dtype'];
				$uid  = $record['uid'];
				$num  = $record['num'];
				$times = $record['times'];
				$bs = $record['bs'];
				$format = $this->cfdConfig['format'];
			    $formatNum = $format[$dtype.'_'.$bs.'_'.$times];
			    if(!$formatNum || $formatNum=='')  throw new Exception('L:'.__LINE__.' 规格错误! format：'.$dtype.'_'.$bs.'_'.$times, 1);

				if(!$this->cfdClass->setDenom($dtype)){//设置计价方式
					writeDebug('['.$datetime.'] 设置计价方式失败！:'.$id, $this->logFile);
					continue;
				}
				$denomConfig = $this->cfdclass->getDenomConfig();
				//更新持仓
				$positionTB = "cfd_cfd_position";
				$where = array('id'=>$id,'flag'=>0);
				$this->db->set('num', 0, FALSE);
				$this->db->set('flag', 1, FALSE);
				$this->db->set('finish_num', 'finish_num+'.$num, FALSE);
				$this->db->set('lastest_modify', $datetime, TRUE);
				$this->db->where($where);
				if(!$this->db->update($positionTB)) throw new Exception('L:'.__LINE__.' 更新持仓失败!', 1); 


				// 计算盈亏
				$yk = $this->cfdClass->countYK($cjPrice,$record['price'], $num, $bs, $record['commission'], $record['overnight']);
				// 实际到帐
				$margin = $this->cfdClass->countBZJ($num, $times, $record['additional']);
				$object = $dtype;
				if($dtype=='ticket'){
					$object = 'cny';
					if($yk<=0) $yk=0;
					$use_value = bcadd($yk, 0, $denomConfig['ykdot']);
					$ykl = $this->cfdClass->countYKL($yk, $times);
				}else{
					$use_value = bcadd($margin, $yk, $denomConfig['ykdot']);
					$ykl = $this->cfdClass->countYKL($yk, $margin);
				}
				$source  = $this->cfdConfig['doing']['settlement']['source'];
				if($use_value>0){
					$where     = "uid='{$uid}'";
					$data_arr  =  array(
						'uid'=> $uid,
						'name' => $record['name'],
						'object' => $object,
						'use_value' => $use_value,
						'source' => $source,
						'add_time' => $datetime,
					);
					if (!$this->cfdClass->add($data_arr)) throw new Exception('L:'.__LINE__.' 平仓加币失败!', 1);
				}
				// 添加 成交记录
			    $log_arr = array(
			        'uid' => $uid,
			        'name' => $record['name'],
		     	    'format' => $formatNum,//主要优化索引
		     	    'dtype' => $dtype,
			        'bs' => $bs,
			        'kp' => 'close',
			        'trade_id' => $id,
			        'times' => $times,
			        'num' => $num,
			        'chi_price' => $record['price'],
			        'price' => $record['price'],
			        'cj_price' => $cjPrice,
			        'commission' => $record['commission'],
			        'overnight' => $record['overnight'],
			        'additional' => $record['additional'],
			        'yk' => $yk,
					'ykl' => $ykl,
			        'source' => $source,
			        'date' => $datetime,
			    );
			    $tradeLogTB = 'cfd_cfd_trade_log';
			    if (!$this->db->insert($tradeLogTB, $log_arr)) throw new Exception('L:'.__LINE__.' 添加交易记录失败', 1);
				// DB 提交修改
				$this->db->trans_complete();
				$this->log_db->trans_complete();
				$this->cfdClass->flushUserCache($uid);
				writeDebug('['.$datetime.'] ChiID: '.$id.' 处理完成!', $this->logFile);
			} catch (Exception $e) {
				$this->db->trans_rollback();
				$this->log_db->trans_rollback();
				writeDebug('['.$datetime.'] ChiID: '.$id.' 处理失败! Err:'.$e->getMessage(), $this->logFile);
			}
		}
	}

	//手动结算
	public function handSettlement($symbol,$cjPrice=0){
		$datetime = date('Y-m-d H:i:s');
		$this->symbol = $symbol;
		//log文件名
		$this->logFile = $symbol."_settlement";
		// 平滑重启
		//加载CFD操作类
		if(!$this->cfdClass->setProduct($symbol,'IB')){//设置产品
			jsonReturn(-1,"无效操作[10001]！");//无效的操作
		}
		$productData = $this->cfdClass->getProductData();
		$settlementArr = explode(',',$productData['settlement']);
		$dst = $this->cfdClass->checkDST($symbol);
		$cur_H = date('H');
		$settlement_H = date('H',strtotime($settlementArr[$dst]));
		// if($settlement_H!=$cur_H){
		// 	writeDebug('['.$datetime.'] 不在结算时间!', $this->logFile);
		// 	die($settlement_H."!=".$cur_H."不在结算时间");
		// }
		//防止MySQL server has gone away
	    $this->db = $this->load->database('default',true);
		$this->log_db = $this->load->database('log',true);
		$this->cfdConfig = $this->cfdClass->getCfdConfig();
		$rs = array();
		//查询所有挂单
		$bidTB = 'cfd_cfd_bid';
		$where = array('flag'=>0,'status'=>3,'name'=>$symbol);
		$query = $this->db->select()->from($bidTB)->where($where)->get();
		$tmp = $query->result_array();
		$rs['bid'] = empty($tmp) ?  array() : $tmp;

		$askTB = 'cfd_cfd_ask';
		$where = array('flag'=>0,'status'=>3,'name'=>$symbol);
		$query = $this->db->select()->from($askTB)->where($where)->get();
		$tmp = $query->result_array();
		$rs['ask'] = empty($tmp) ?  array() : $tmp;

		foreach ($rs as $actionType => $records) {
			if (!empty($records)) {
				writeDebug('['.$datetime.'] '.$actionType.'自动撤单开始!', $this->logFile);
				foreach ($records as $record) {
					$this->cancel($actionType, $record['id']);
				}
				writeDebug('['.$datetime.'] '.$actionType.'自动撤单结束!', $this->logFile);
			}
		}
		//结算-自动平仓
		$positionTB = 'cfd_cfd_position';
		$where = array('flag'=>0,'name'=>$symbol,'lastest_modify<='=>'2016-07-15 05:00:00');
		$query = $this->db->select()->from($positionTB)->where($where)->get();
		$chiArr = $query->result_array();
		print_r($chiArr);
		die;
		$redisData = $this->cfdClass->redisAllData();
		// $cjPrice = $redisData['trade']['LAST_PRICE'];
		echo "结算价：".$cjPrice."\n";
		if($cjPrice<=0){
			echo "cjPrice错误：".$cjPrice."\n";
			writeDebug('['.$datetime.'] cjPrice错误:'.$cjPrice, $this->logFile);
			die;
		}
		if(!empty($chiArr)) foreach($chiArr as $record){
			try {
				$this->db->trans_start();//开始事务
				$this->log_db->trans_start();//开始事务

				$id = $record['id'];
				$dtype = $record['dtype'];
				$uid  = $record['uid'];
				$num  = $record['num'];
				$times = $record['times'];
				$bs = $record['bs'];
				$format = $this->cfdConfig['format'];
			    $formatNum = $format[$dtype.'_'.$bs.'_'.$times];
			    if(!$formatNum || $formatNum=='')  throw new Exception('L:'.__LINE__.' 规格错误! format：'.$dtype.'_'.$bs.'_'.$times, 1);

				if(!$this->cfdClass->setDenom($dtype)){//设置计价方式
					writeDebug('['.$datetime.'] 设置计价方式失败！:'.$id, $this->logFile);
					continue;
				}
				$denomConfig = $this->cfdclass->getDenomConfig();
				//更新持仓
				$positionTB = "cfd_cfd_position";
				$where = array('id'=>$id,'flag'=>0);
				$this->db->set('num', 0, FALSE);
				$this->db->set('flag', 1, FALSE);
				$this->db->set('finish_num', 'finish_num+'.$num, FALSE);
				$this->db->set('lastest_modify', $datetime, TRUE);
				$this->db->where($where);
				if(!$this->db->update($positionTB)) throw new Exception('L:'.__LINE__.' 更新持仓失败!', 1); 


				// 计算盈亏
				$yk = $this->cfdClass->countYK($cjPrice,$record['price'], $num, $bs, $record['commission'], $record['overnight']);
				// 实际到帐
				$margin = $this->cfdClass->countBZJ($num, $times, $record['additional']);
				$object = $dtype;
				if($dtype=='ticket'){
					$object = 'cny';
					if($yk<=0) $yk=0;
					$use_value = bcadd($yk, 0, $denomConfig['ykdot']);
					$ykl = $this->cfdClass->countYKL($yk, $times);
				}else{
					$use_value = bcadd($margin, $yk, $denomConfig['ykdot']);
					$ykl = $this->cfdClass->countYKL($yk, $margin);
				}
				$source  = $this->cfdConfig['doing']['settlement']['source'];
				if($use_value>0){
					$where     = "uid='{$uid}'";
					$data_arr  =  array(
						'uid'=> $uid,
						'name' => $record['name'],
						'object' => $object,
						'use_value' => $use_value,
						'source' => $source,
						'add_time' => $datetime,
					);
					if (!$this->cfdClass->add($data_arr)) throw new Exception('L:'.__LINE__.' 平仓加币失败!', 1);
				}
				// 添加 成交记录
			    $log_arr = array(
			        'uid' => $uid,
			        'name' => $record['name'],
		     	    'format' => $formatNum,//主要优化索引
		     	    'dtype' => $dtype,
			        'bs' => $bs,
			        'kp' => 'close',
			        'trade_id' => $id,
			        'times' => $times,
			        'num' => $num,
			        'chi_price' => $record['price'],
			        'price' => $record['price'],
			        'cj_price' => $cjPrice,
			        'commission' => $record['commission'],
			        'overnight' => $record['overnight'],
			        'additional' => $record['additional'],
			        'yk' => $yk,
					'ykl' => $ykl,
			        'source' => $source,
			        'date' => $datetime,
			    );
			    $tradeLogTB = 'cfd_cfd_trade_log';
			    if (!$this->db->insert($tradeLogTB, $log_arr)) throw new Exception('L:'.__LINE__.' 添加交易记录失败', 1);
				// DB 提交修改
				$this->db->trans_complete();
				$this->log_db->trans_complete();
				$this->cfdClass->flushUserCache($uid);
				writeDebug('['.$datetime.'] ChiID: '.$id.' 处理完成!', $this->logFile);
			} catch (Exception $e) {
				$this->db->trans_rollback();
				$this->log_db->trans_rollback();
				writeDebug('['.$datetime.'] ChiID: '.$id.' 处理失败! Err:'.$e->getMessage(), $this->logFile);
			}
		}
	}



	// 市价开仓
	private function marketPrice($actionType, $orderData) {
		$datetime  = date('Y-m-d H:i:s'); // 记录时间
		$redisData = $this->cfdClass->redisAllData();
		// $hedge = getHedgeData($orderData, $redisData['hedge']);
		$id = $orderData['id'];//订单ID
		try {
			$this->db->trans_start();//开始事务
			$this->log_db->trans_start();//开始事务
			// 开始事务
			$this->redis->multi();

			// 更新订单状态
			$table = "cfd_cfd_".$actionType;
			$where = array('id'=>$id,'status'=>0,'flag'=>0,'type'=>0);
			$this->db->set('status', 1, FALSE);
			$this->db->where($where);
			if(!$this->db->update($table)) throw new Exception('L:'.__LINE__.' 更新订单状态失败!', 1);

			$flushUserCache = false; // 判断是否刷新用户缓存

			$new_com = $redisData['trade']["WCP_".strtoupper($actionType).'_COM'];//当前佣金点数 
			// 是否在波动范围内
			if ($this->checkFloatingRange($orderData, $actionType, $new_com, $datetime)) {
				// 检查是否需要对冲
				$netNum   = $actionType == 'bid' ? $orderData['num'] : bcmul($orderData['num'], '-1');
				// $cjPrice = $actionType == 'bid' ? $redisData['trade']['ASK_PRICE'] : $redisData['trade']['BID_PRICE']; // 计算成交价
				// 只用最新价成交
				$cjPrice = $redisData['trade']['LAST_PRICE']; // 计算成交价

				// 更新成交记录
				$table = "cfd_cfd_".$actionType;
				$where = array('id'=>$id,'status'=>1);
				$this->db->set('status', 4, FALSE);
				$this->db->set('flag', 1, FALSE);
				$this->db->set('cjnum', 'num', FALSE);
				$this->db->set('lastest_modify', $datetime, TRUE);
				$this->db->where($where);
				if(!$this->db->update($table)) throw new Exception('L:'.__LINE__.' 更新成交记录!', 1); 

				// // 更新净持仓Mysql
				// $table = 'cfd_cfd_hedge';
				// $where = array('name'=>$orderData['name']);
				// $this->db->set('net_position', 'net_position+'.$netNum, FALSE);
				// $this->db->set('lastest_modify', $datetime, TRUE);
				// $this->db->where($where);
				// if(!$this->db->update($table)) throw new Exception('L:'.__LINE__.' 更新净持仓失败-mysql!', 1); 

				// 更新 对冲数据
				// $hedge[$actionType]    = bcadd($hedge[$actionType], $orderData['num']);
				// $hedge['net_position'] = bcadd($hedge['net_position'], $netNum);
				// $hedge_key             = $this->cfdClass->getCommonConfig('redis_hedge');
				// monitorHedgeForRedis($hedge,$netNum,'marketPrice|'.$actionType);
				// if (!$redis->hMSet($hedge_key, $hedge)) throw new Exception('L:'.__LINE__.' 更新净持仓失败-redis!', 1);

				// 更新佣金指数
				// updateCommission($hedge,$redisData);

				// 市价单不考虑佣金限制
				$this->addChiRecord($orderData, $actionType, $cjPrice ,$orderData['commission'], $datetime);
			} else {
				// 撤单退币, 更新 flush
				$flushUserCache = $orderData['uid'];
			}
			
			// DB 提交修改
			$this->db->trans_complete();
			$this->log_db->trans_complete();
			// Redis 提交修改
			$this->redis->exec();
			$flushUserCache == false ? '' : $this->cfdClass->flushUserCache($flushUserCache);
			writeDebug('['.$datetime.'] '.$actionType.'|'.$id.' 处理完成!', $this->logFile);
		} catch (Exception $e) {
			$this->db->trans_rollback();
			$this->log_db->trans_rollback();
			$this->redis->discard();
			writeDebug('['.$datetime.'] Err: '.$e->getMessage(), $this->logFile);
		}
	}


	public function marketPricePing($actionType, $orderData) {
		$id = $orderData['id'];
		$posid = $orderData['posid'];//持仓ID
		$uid = $orderData['uid'];
		$num = $orderData['num'];
		$times = $orderData['times'];//保证金比例
		$datetime = date('Y-m-d H:i:s'); // 记录时间

		// 更新订单状态
		$table = "cfd_cfd_".$actionType;
		$where = array('id'=>$id,'status'=>0,'flag'=>0,'type'=>0);
		$this->db->set('status', 5, FALSE);
		$this->db->where($where);
		if(!$this->db->update($table)) throw new Exception('L:'.__LINE__.' 更新订单状态失败!', 1);
		//检查持仓订单
		$positionTB = "cfd_cfd_position";
		$where = array('id'=>$posid,'flag'=>0,'num>'=>'0');
		$query = $this->db->select()->from($positionTB)->where($where)->limit(1)->get();
		if ($query->row()){
			$chiData = $query->row_array();
		}else{
			writeDebug('['.$datetime.'] Err: L:'.__LINE__.' Action: Market'.$actionType.'_ping|'.$id.' 查不到可以平仓的持仓记录!', $this->logFile);
			return false;
		}

		//检查平仓数量
		if(bccomp($orderData['num'],$chiData['num'],0) > 0){
			writeDebug('['.$date.'] Err: L:'.__LINE__.' Action: Market'.$actionType.'_ping|'.$id.' 平仓数量错误!', $this->logFile);
			return false;
		}
		$redisData = $this->cfdClass->redisAllData();
		// 不需要检查佣金波动范围
		// $hedge = getHedgeData($orderData, $redisData['hedge']); // data = array('bid', 'ask', 'net_position', 'position', 'a', 'index');
		try {
			$this->db->trans_start();//开始事务
			$this->log_db->trans_start();//开始事务
			// 开始事务
			$this->redis->multi();

			// 更新订单状态为处理中
			$table = "cfd_cfd_".$actionType;
			$where = array('id'=>$id,'status'=>5,'flag'=>0,'type'=>0);
			$this->db->set('status', 1, FALSE);
			$this->db->where($where);
			if(!$this->db->update($table)) throw new Exception('L:'.__LINE__.' 更新订单状态失败!', 1);

			$positionTB = "cfd_cfd_position";
			$where = array('id'=>$posid,'flag'=>0);
			$this->db->set('num', 'num-'.$num, FALSE);
			$this->db->set('block_num', 'block_num+'.$num, FALSE);
			$this->db->set('lastest_modify', $datetime, TRUE);
			$this->db->where($where);
			if(!$this->db->update($positionTB)) throw new Exception('L:'.__LINE__.' 冻结持仓失败!', 1); 


			$positionTB = "cfd_cfd_position";
			$where = array('id'=>$posid);
			$query = $this->db->select()->from($positionTB)->where($where)->limit(1)->get();

			$flushUserCache = false; // 判断是否刷新用户缓存
			$new_com = 0;
			// 检查是否需要对冲
			$netNum = $actionType == 'bid' ? bcmul($orderData['num'],'-1') : $orderData['num'];
			// $cjPrice = $actionType == 'bid' ? $redisData['trade']['BID_PRICE'] : $redisData['trade']['ASK_PRICE']; // 计算成交价
			$cjPrice = $redisData['trade']['LAST_PRICE']; // 计算成交价

			// 更新成交记录
			$table = "cfd_cfd_".$actionType;
			$where = array('id'=>$id,'status'=>1);
			$this->db->set('status', 4, FALSE);
			$this->db->set('flag', 1, FALSE);
			$this->db->set('cjnum', 'num', FALSE);
			$this->db->set('lastest_modify', $datetime, TRUE);
			$this->db->where($where);
			if(!$this->db->update($table)) throw new Exception('L:'.__LINE__.' 更新成交记录!', 1);

			// 更新净持仓Mysql
			// $table = 'cfd_cfd_hedge';
			// $where = array('name'=>$orderData['name']);
			// $this->db->set('net_position', 'net_position+'.$netNum, FALSE);
			// $this->db->set('lastest_modify', $datetime, TRUE);
			// $this->db->where($where);
			// if(!$this->db->update($table)) throw new Exception('L:'.__LINE__.' 更新净持仓失败-mysql!', 1); 

			// // 更新 对冲数据
			// $hedge[$actionType]    = bcsub($hedge[$actionType], $orderData['num']);
			// $hedge_key             = $this->cfdClass->getCommonConfig('redis_hedge');
			// monitorHedgeForRedis($hedge,$netNum,'marketPricePing|'.$actionType);
			// if (!$redis->hMSet($hedge_key, $hedge)) throw new Exception('L:'.__LINE__.' 更新净持仓失败-redis!', 1);

			// // 更新佣金指数
			// updateCommission($hedge,$redisData);
			
			// 修改持仓记录 && 返回 uid
			$flushUserCache = $this->reduceChiRecord($orderData, $actionType, $cjPrice, $datetime);

			// DB 提交修改
			$this->db->trans_complete();
			$this->log_db->trans_complete();
			// Redis 提交修改
			$this->redis->exec();
			$flushUserCache == false ? '' : $this->cfdClass->flushUserCache($flushUserCache);
			writeDebug('['.$datetime.'] '.$actionType.'_ping|'.$id.' 处理完成!', $this->logFile);
		} catch (Exception $e) {
			$this->db->trans_rollback();
			$this->log_db->trans_rollback();
			$this->redis->discard();
			writeDebug('['.$datetime.'] Err: '.$e->getMessage(), $this->logFile);
		}
	}

	function cancel($actionType, $id, $abnormal = false) {
		$datetime  = date('Y-m-d H:i:s');
		try {
			$this->db->trans_start();//开始事务
			$this->log_db->trans_start();//开始事务


			$bsTB = "cfd_cfd_".$actionType;
			if (!$abnormal) {
				$where = array('id'=>$id,'flag'=>0,'status'=>3,'type'=>1);
				$this->db->set('status', 4, FALSE);
				$this->db->set('flag', 1, FALSE);
				$this->db->where($where);
				$source = $this->cfdConfig['doing'][$actionType]['cancel']['source'];
			} else {
				$where = array('id'=>$id,'flag'=>0,'status'=>0);
				$this->db->set('status', 4, FALSE);
				$this->db->set('flag', 1, FALSE);
				$this->db->where($where);
				$source = $this->cfdConfig['doing'][$actionType]['autoCancel']['source'];
			}
			if(!$this->db->update($bsTB)) throw new Exception('L:'.__LINE__.' 更新订单状态失败!', 1); 

			//检查订单
			$where = array('id'=>$id);
			$query = $this->db->select()->from($bsTB)->where($where)->limit(1)->get();
			if ($query->row()){
				$orderData = $query->row_array();
			}else{
				 throw new Exception('L:'.__LINE__.' 查询订单失败!', 1);
			}
			$flush = false;
			$num = $orderData['num'];
			$uid = $orderData['uid'];
			$format = $this->cfdConfig['format'];
		 	$formatNum = $format[$orderData['dtype'].'_'.$actionType.'_'.$orderData['times']];
			if(!$formatNum || $formatNum=='')  throw new Exception('L:'.__LINE__.' 规格错误! format：'.$orderData['dtype'].'_'.$actionType.'_'.$orderData['times'], 1);
			// 如果撤销开仓则退币
			$log_arr = array(
		        'uid' => $uid,
		        'name' => $orderData['name'],
	     	    'format' => $formatNum,//主要优化索引
	     	    'dtype' => $orderData['dtype'],
		        'bs' => $actionType,
		        'kp' => $orderData['kp'],
		        'trade_id' => $orderData['id'],
		        'times' => $orderData['times'],
		        'num' => $num,
		        'price' => $orderData['price'],
		        'cj_price' => 0,
		        'commission' => $orderData['commission'],
		        'overnight' => 0,
		        'additional' => 0,
		        'source' => $source,
		        'date' => $datetime,
		    );
		    $tradeLogTB = 'cfd_cfd_trade_log';
		    if (!$this->db->insert($tradeLogTB, $log_arr)) throw new Exception('L:'.__LINE__.' 添加撤单记录失败', 1);

			if ($orderData['kp'] == 'open') {
				// 退币到用户账户
				$use_value = $this->cfdClass->countBZJ($num, $orderData['times'],0,'open');
				$data_arr  =  array(
					'uid'=> $uid,
					'name' => $orderData['name'],
					'object' => $orderData['dtype'],
					'use_value' => $use_value,
					'source' => $source,
					'add_time' => $datetime,
				);
				if (!$this->cfdClass->add($data_arr)) throw new Exception('L:'.__LINE__.' 撤单失败!', 1);
				// 更新用户Cache
				$flush = $uid;
			} else {
				if (!$abnormal) {
					$posid = $orderData['posid'];
					$positionTB = "cfd_cfd_position";
					$where = array('id'=>$posid,'uid'=>$uid,'flag'=>0,'block_num>='=>$num);
					$this->db->set('block_num', 'block_num-'.$num, FALSE);
					$this->db->set('num', 'num+'.$num, FALSE);
					$this->db->set('lastest_modify', $datetime, TRUE);
					$this->db->where($where);
					if(!$this->db->update($positionTB)) throw new Exception('L:'.__LINE__.' 更新持仓失败!', 1);
				}
			}
			$this->db->trans_complete();
			$this->log_db->trans_complete();
			$flush == false ? '' : $this->cfdClass->flushUserCache($flush);
			writeDebug('['.$datetime.'] '.'cancel|'.$actionType.'|'.$id.' 处理完成!', $this->logFile);
		} catch (Exception $e) {
			$this->db->trans_rollback();
			$this->log_db->trans_rollback();
			writeDebug('['.$datetime.'] 撤单失败! Err: '.$e->getMessage(), $this->logFile);
		}
	}


	// 检查爆仓
	public function checkBao($actionType, $datetime) {
		$symbol = $this->symbol;
		$positionTB = "cfd_cfd_position";
		$bsTB = "cfd_cfd_".$actionType;
		$datetime = date('Y-m-d H:i:s');
		//规格
		$format = $this->cfdConfig['format'];
		$redisData = $this->cfdClass->redisAllData();
		// $denomConfig = $this->cfdclass->getDenomConfig();
		//查询满足爆仓条件的持仓信息
		if ($actionType == 'bid') {
			// $avg_price = $redisData['trade']['BID_PRICE']; // 计算成交价
			$avg_price = $redisData['trade']['LAST_PRICE']; // 计算成交价
			$where = array('flag'=>0, 'bs'=>$actionType,'bao_price>='=>$avg_price,'name'=>$symbol);
		} else {
			// $avg_price = $redisData['trade']['ASK_PRICE']; // 计算成交价
			$avg_price = $redisData['trade']['LAST_PRICE']; // 计算成交价
			$where = array('flag'=>0, 'bs'=>$actionType,'bao_price<='=>$avg_price,'name'=>$symbol);
		}
		$query = $this->db->select()->from($positionTB)->where($where)->get();
		$rs = $query->result_array();
		if (!empty($rs)) {
			foreach ($rs as $record) {
				$posid = $record['id'];
				$uid = $record['uid'];
				$dtype = $record['dtype'];
				$times = $record['times'];
				if(!$this->cfdClass->setDenom($dtype)){//设置计价方式
					writeDebug('['.$datetime.'] '.__LINE__.' 设置计价方式失败', $this->logFile);
					continue;
				}
				$formatNum = $format[$dtype.'_'.$actionType.'_'.$times];
				if(!$formatNum || $formatNum=='')  throw new Exception('L:'.__LINE__.' 规格错误! format：'.$dtype.'_'.$actionType.'_'.$times, 1);
				try {
					$this->db->trans_start();//开始事务
					$this->log_db->trans_start();//开始事务
					// 开始事务
					$this->redis->multi();
					// 检查是否自动追加
					if (!$this->checkBuCang($record, $datetime)) {
						// 更新持仓记录的状态
						$where = array('id'=>$posid,'flag'=>0);
						$this->db->set('flag', 2, FALSE);
						$this->db->where($where);
						if(!$this->db->update($positionTB)) throw new Exception('L:'.__LINE__.' 更新持仓状态失败!', 1); 
						if ($record['block_num'] > 0) {//有平仓挂单
							$where = array('uid'=>$uid, 'posid'=>$posid, 'flag'=>0);
							$query = $this->db->select()->from($bsTB)->where($where)->where_in('status',array(0,3))->get();
							$tmp = $query->result_array();
							if (empty($tmp)) throw new Exception('L:'.__LINE__.' 查询平仓记录失败!', 1);
							foreach ($tmp as $val) {
								$trade_id = $val['id'];
								$gNum = $val['num'];
							    $gFormatNum = $format[$val['dtype'].'_'.$actionType.'_'.$val['times']];
							    if(!$gFormatNum || $gFormatNum=='')  throw new Exception('L:'.__LINE__.' 规格错误! format：'.$val['dtype'].'_'.$actionType.'_'.$val['times'], 1);
								// 更新持仓记录的状态
								$where = array('id'=>$trade_id);
								$this->db->set('flag', 1, FALSE);
								$this->db->set('status', 4, FALSE);
								$this->db->set('lastest_modify', $datetime, TRUE);
								$this->db->where($where);
								if(!$this->db->update($bsTB)) throw new Exception('L:'.__LINE__.' 更新订单状态失败!', 1);
								
								// 更新持仓记录的状态
								$where = array('id'=>$posid,'block_num>='=>$gNum);
								$this->db->set('block_num', 'block_num-'.$gNum, FALSE);
								$this->db->set('num', 'num+'.$gNum, FALSE);
								$this->db->where($where);
								if(!$this->db->update($positionTB)) throw new Exception('L:'.__LINE__.' 更新持仓状态失败!', 1);

								// 添加撤单记录
							    $log_arr = array(
							        'uid' => $uid,
							        'name' => $val['name'],
						     	    'format' => $gFormatNum,//主要优化索引
						     	    'dtype' => $val['dtype'],
							        'bs' => $val['bs'],
							        'kp' => $val['kp'],
							        'trade_id' => $trade_id,
							        'times' => $val['times'],
							        'num' => $gNum,
							        'price' => $val['price'],
							        'cj_price' => 0,
							        'commission' => 0,
							        'overnight' => 0,
							        'additional' => 0,
							        'source' => $this->cfdConfig['doing'][$actionType]['cancel']['source'],
							        'date' => $datetime,
							    );
							    $table = 'cfd_cfd_trade_log';
							    if (!$this->db->insert($table, $log_arr)) throw new Exception('L:'.__LINE__.' 添加交易记录失败', 1);
							}
						}

						// 更新持仓为爆仓
						$where = array('id'=>$posid,'flag'=>2,'uid'=>$uid);
						$this->db->set('bao_num', 'num', FALSE);
						$this->db->set('num', 0, FALSE);
						$this->db->set('flag', 1, FALSE);
						$this->db->set('lastest_modify', $datetime, TRUE);
						$this->db->where($where);
						if(!$this->db->update($positionTB)) throw new Exception('L:'.__LINE__.' 更新持仓状态失败!', 1);

						// 重新查询一次
						$where = array('id'=>$posid);
						$query = $this->db->select()->from($positionTB)->where($where)->limit(1)->get();
						if ($query->row()){
							$record = $query->row_array();
						}else{
							writeDebug('['.$datetime.'] Err: L:'.__LINE__.' 查询持仓记录失败', $this->logFile);
							return false;
						}

						// 计算盈亏
						$yk = del0(bcmul($this->cfdClass->countBZJ($record['bao_num'], $record['times'], $record['additional']),-1,6));
						
						if($record['dtype']=='ticket'){
							$yk = 0;
						}

						// 添加爆仓记录
						$log_arr = array(
					        'uid' => $uid,
					        'name' => $record['name'],
				     	    'format' => $formatNum,//主要优化索引
				     	    'dtype' => $record['dtype'],
					        'bs' => $actionType,
					        'kp' => 'close',
					        'trade_id' => $record['id'],
					        'times' => $record['times'],
					        'num' => $record['bao_num'],
					        'chi_price' => $record['price'],
					        'price' => $record['price'],
					        'cj_price' => $avg_price,
					        'commission' => $record['commission'],
					        'overnight' => $record['overnight'],
					        'additional' => $record['additional'],
					        'yk' => $yk,
							'ykl' => '-100',
					        'source' => $this->cfdConfig['doing']['bao']['source'],
					        'date' => $datetime,
					    );
					    $table = 'cfd_cfd_trade_log';
					    if (!$this->db->insert($table, $log_arr)) throw new Exception('L:'.__LINE__.' 添加爆仓记录失败', 1);

						// $hedge   = getHedgeData($record); // data = array('bid', 'ask', 'net_position', 'position', 'a', 'index');			
						// // 检查是否需要对冲
						// $net_num = $actionType == 'bid' ? bcmul($record['bao_num'], '-1') : $record['bao_num'];
						// if(false){//晚上才对冲
						// 	// 更新净持仓Mysql
						// 	$table   = table($params['hedgeTB']);
						// 	$code    = $record['code'];
						// 	$sql     = "UPDATE {$table} SET net_position=net_position+{$net_num}, lastest_modify='{$datetime}' WHERE code='{$code}'";
						// 	if (!$write_conn->exec($sql)) throw new Exception('L:'.__LINE__.' 更新净持仓失败-mysql!', 1);
						// 	$hedge['net_position'] = bcadd($hedge['net_position'], $net_num);
						// }
						// // 更新 对冲数据
						// $hedge[$actionType]    = bcsub($hedge[$actionType], $record['bao_num']);
						// $hedge_key             = $lib->getCommonConfig('redis_hedge');
						// monitorHedgeForRedis($hedge,$net_num,'checkBao|'.$actionType);
						// if (!$redis->hMSet($hedge_key, $hedge)) throw new Exception('L:'.__LINE__.' 更新净持仓失败-redis!', 1);
						// // 更新佣金指数
						// updateCommission($hedge);

						writeDebug('['.$datetime.'] 爆仓处理完毕! ChiID: '. $record['id'], $this->logFile);
					} else {
						writeDebug('['.$datetime.'] 追加保证金成功! ChiID: '. $record['id'], $this->logFile);
					}
					// DB 提交修改
					$this->db->trans_complete();
					$this->log_db->trans_complete();
					// Redis 提交修改
					$this->redis->exec();
					$this->cfdClass->flushUserCache($uid);
				} catch (Exception $e) {
					$this->db->trans_rollback();
					$this->log_db->trans_rollback();
					$this->redis->discard();
					writeDebug('['.$datetime.'] 爆仓处理出错! Err: '. $e->getMessage(), $this->logFile);
				}
			}
			writeDebug('['.$datetime.'] 符合条件的爆仓处理完毕!', $this->logFile);	
		} else {
			writeDebug('['.$datetime.'] 没有符合条件的爆仓!', $this->logFile);	
		}
	}

	private function checkFirstBao($symbol, $data) {
		foreach ($data as $key => $val) {
			$$key = $val;
		}
		unset($data);
		$queue2Key = $this->cfdConfig['common']['queue2']."_".$symbol;
		$this->redis = $this->cfdClass->getRedis();
		$positionTB = "cfd_cfd_position";
		//防止MySQL server has gone away
	    $this->db = $this->load->database('default',true);
		$this->log_db = $this->load->database('log',true);
		try {
			if ($check_bid) {
				$bidArr = array(
					'flag' => 0,
					'bs' => 'bid',
					'bao_price>=' => $bid_price,
					'name' => $symbol
				);
				$this->db->where($bidArr);
				$this->db->from($positionTB);
				$bid_total = $this->db->count_all_results();
				if($bid_total>0){
					writeDebug('['.date('Y-m-d H:i:s').'] bao_bid: '.$bid_price." total=".$bid_total, $this->logFile);
					if (!$this->redis->lPush($queue2Key, 'bao_bid')) throw new Exception('L:'.__LINE__.' 队列推送失败!', 1);
				}
			}
			if ($check_ask) {
				$askArr = array(
					'flag' => 0,
					'bs' => 'ask',
					'bao_price<=' => $ask_price,
					'name' => $symbol
				);
				$this->db->where($askArr);
				$this->db->from($positionTB);
				$ask_total = $this->db->count_all_results();
				if($ask_total>0){
					writeDebug('['.date('Y-m-d H:i:s').'] bao_ask: '.$ask_price." total=".$ask_total, $this->logFile);
					if (!$this->redis->lPush($queue2Key, 'bao_ask')) throw new Exception('L:'.__LINE__.' 队列推送失败!', 1);
				}
			}
		} catch (Exception $e) {
			writeDebug('['.date('Y-m-d H:i:s').'] 检查爆仓失败! Err: '. $e->getMessage(), $this->logFile);
		}
	}

	private function checkBuCang($posData, $datetime){
		return false;
	}

	private function updateCommission(){
		$this->cfdClass->updateCommission();
	}

	/**
	 * 添加持仓记录 || 合并持仓
	 * @param array $orderData        委托订单的数据
	 * @param string $actionType bid | ask
	 * @param float $cjPrice  均价
	 * @param int $new_com    最新的佣金
	 * @param date $date      日期
	 * @return  void
	 */
	private function addChiRecord($orderData, $actionType, $cjPrice, $new_com, $datetime){
	    $uid   = $orderData['uid'];
	    $dtype = $orderData['dtype'];
	    $times = $orderData['times'];
	    //规格
	    $format = $this->cfdConfig['format'];
	    $formatNum = $format[$dtype.'_'.$actionType.'_'.$times];
	    if(!$formatNum || $formatNum=='')  throw new Exception('L:'.__LINE__.' 规格错误! format：'.$dtype.'_'.$actionType.'_'.$times, 1);

	    // 判断市价还是限价,如果是现价就拿数据库中的价格
	    if ($orderData['type'] == '1' AND $cjPrice == 0) $cjPrice = $orderData['price'];
	    // 查询持仓信息
		$positionTB = "cfd_cfd_position";
		$where = array('uid'=>$uid, 'name'=>$orderData['name'], 'format'=>$formatNum, 'flag'=>0);
		$query = $this->db->select()->from($positionTB)->where($where)->limit(1)->get();
		// if (!$query->row()) {//没有持仓
		if (true) {//没有持仓
	        $baoPrice = $this->cfdClass->countBaoPrice($cjPrice, $new_com, 0, $actionType, $times); // 计算加权爆仓价
	        $data_arr  = array(
	            'uid' => $uid,
	            'name' => $orderData['name'],
	            'format' => $formatNum,//主要优化索引
	            'dtype' => $orderData['dtype'],
	            'bs' => $actionType,
	            'times' => $times,
	            'flag' => 0,
	            'num' => $orderData['num'],
	            'block_num' => 0,
	            'bao_num' => 0,
	            'finish_num' => 0,
	            'commission' => $new_com,
	            'overnight' => 0,
	            'price' => $cjPrice,
	            'bao_price' => $baoPrice,
	            'lastest_modify' => $datetime,
	        );
	        if (!$this->db->insert($positionTB,$data_arr)) throw new Exception('L:'.__LINE__.' 添加持仓记录失败!', 1);
		}else{
			//持仓信息
			$positionData = $query->row_array();
			 // 计算加权均价
	        $old_num = bcadd($positionData['num'], $positionData['block_num']);
	        $new_num = $orderData['num'];
	        $data_arr = array(
	            'old_num'   => $old_num,
	            'old_price' => $positionData['price'],
	            'new_num'   => $new_num,
	            'new_price' => $cjPrice,
	            'bs' => $actionType,
	        );
	        //计算新的持仓均价
	        $newPrice = $this->cfdClass->countAvgPrice($data_arr);

	        // 计算加权佣金
	        $data_arr = array(
	            'old_num' => $old_num,
	            'old_com' => $positionData['commission'],
	            'new_num' => $new_num,
	            'new_com' => $new_com,
	        );
	        $newCom = $this->cfdClass->countAvgCommission($data_arr);

	        // 计算加权过夜费
	        $data_arr = array(
	            'old_num' => $old_num,
	            'old_fee' => $positionData['overnight'],
	            'new_num' => $new_num,
	            'new_fee' => 0,
	        );
	        $newOvernight = $this->cfdClass->countAvgOvernightFee($data_arr);

	        // 计算加权追加资金
	        $data_arr = array(
	            'old_num' => $old_num,
	            'old_com' => $positionData['additional'],
	            'new_num' => $new_num,
	            'new_com' => 0,
	        );
	        $newAdditional = $this->cfdClass->countAvgCommission($data_arr);

	        // 计算加权爆仓价
	        $newBaoPrice = $this->cfdClass->countBaoPrice($newPrice, $newCom, $newOvernight, $actionType, $times, $newAdditional);

	        // 更新持仓
	        $posid = $positionData['id'];
			$table = 'cfd_cfd_position';
			$where = array('id'=>$posid,'flag'=>0);
			$this->db->set('num', 'num+'.$new_num, FALSE);
			$this->db->set('commission', $newCom, FALSE);
			$this->db->set('overnight', $newOvernight, FALSE);
			$this->db->set('price', $newPrice, FALSE);
			$this->db->set('bao_price', $newBaoPrice, FALSE);
			$this->db->set('additional', $newAdditional, FALSE);
			$this->db->set('lastest_modify', $datetime, TRUE);
			$this->db->where($where);
			if(!$this->db->update($table)) throw new Exception('L:'.__LINE__.' 更新持仓记录失败!', 1); 
		}
		$denomConfig = $this->cfdclass->getDenomConfig();
	    // 添加 成交记录
	    $log_arr = array(
	        'uid' => $orderData['uid'],
	        'name' => $orderData['name'],
     	    'format' => $formatNum,//主要优化索引
     	    'dtype' => $orderData['dtype'],
	        'bs' => $actionType,
	        'kp' => 'open',
	        'trade_id' => $orderData['id'],
	        'times' => $times,
	        'num' => $orderData['num'],
	        'price' => $orderData['price'],
	        'cj_price' => $cjPrice,
	        'pre_open_comm' => $denomConfig['extra_com'],
	        'commission' => $new_com,
	        'overnight' => 0,
	        'additional' => 0,
	        'source' => $this->cfdConfig['doing'][$actionType]['deal']['source'],
	        'date' => $datetime,
	    );
	    $table = 'cfd_cfd_trade_log';
	    if (!$this->db->insert($table, $log_arr)) throw new Exception('L:'.__LINE__.' 添加交易记录失败', 1);
	}

	/**
	 * 减去仓位
	 * @param  [type] $orderData  [description]
	 * @param  [type] $actionType [description]
	 * @param  [type] $cjPrice    [description]
	 * @param  [type] $datetime   [description]
	 * @return [type]             [description]
	 */
	private function reduceChiRecord($orderData, $actionType, $cjPrice, $datetime) {
		$denomConfig = $this->cfdclass->getDenomConfig();
		$uid = $orderData['uid'];
		$dtype = $orderData['dtype'];
		$num = $orderData['num'];
		$posid = $orderData['posid'];
		$times = $orderData['times'];
		// 判断市价还是限价
		$cjPrice == 0 ? $cjPrice = $orderData['price'] : '';	
		//规格
	    $format = $this->cfdConfig['format'];
	    $formatNum = $format[$dtype.'_'.$actionType.'_'.$times];
	    if(!$formatNum || $formatNum=='')  throw new Exception('L:'.__LINE__.' 规格错误! format：'.$dtype.'_'.$actionType.'_'.$times, 1);

		$positionTB = "cfd_cfd_position";
		$where = array('id'=>$posid, "block_num>="=>$num, 'flag'=>0);
		$query = $this->db->select()->from($positionTB)->where($where)->limit(1)->get();
		if ($query->row()){
			$posData = $query->row_array();
		}else{
			throw new Exception('L:'.__LINE__.' id='.$posid.' block_num>'.$num.' flag=0 没有符合条件的持仓记录!', 1);
		}
		// 如果有该记录 - 修改持仓记录
		$where = array('id'=>$posid,'flag'=>0);
		$this->db->set('block_num', 'block_num-'.$num, FALSE);
		$this->db->set('finish_num', 'finish_num+'.$num, FALSE);
		$this->db->set('lastest_modify', $datetime, TRUE);
		$this->db->where($where);
		if(!$this->db->update($positionTB)) throw new Exception('L:'.__LINE__.' 平仓失败!', 1); 
		// 结束该持仓记录
		$where = array('id'=>$posid, 'num'=>0, 'block_num'=>0);
		$query = $this->db->select()->from($positionTB)->where($where)->limit(1)->get();
		if ($query->row()){
			$where = array('id'=>$posid, 'num'=>0, 'block_num'=>0);
			$this->db->set('flag', 1, FALSE);
			$this->db->where($where);
			if(!$this->db->update($positionTB)) throw new Exception('L:'.__LINE__.' 结束持仓失败!', 1); 
		}
		// 计算盈亏
		$yk = $this->cfdClass->countYK($cjPrice,$posData['price'], $num, $actionType, $posData['commission'], $posData['overnight']);
		// 实际到帐
		$margin = $this->cfdClass->countBZJ($num, $posData['times'], $posData['additional']);
		if($dtype=='ticket'){
			$dtype = 'cny';
			if($yk<=0) $yk=0;
			$use_value = bcadd($yk, 0, $denomConfig['ykdot']);
			$ykl = $this->cfdClass->countYKL($yk, $posData['times']);
		}else{
			$use_value = bcadd($margin, $yk, $denomConfig['ykdot']);
			$ykl = $this->cfdClass->countYKL($yk, $margin);
		}
		$source  = $this->cfdConfig['doing'][$actionType]['close']['source'];
		if($use_value>0){
			$where     = "uid='{$uid}'";
			$data_arr  =  array(
				'uid'=> $uid,
				'name' => $orderData['name'],
				'object' => $dtype,
				'use_value' => $use_value,
				'source' => $source,
				'add_time' => $datetime,
			);
			if (!$this->cfdClass->add($data_arr)) throw new Exception('L:'.__LINE__.' 平仓加币失败!', 1);
		}

		 // 添加 成交记录
	    $log_arr = array(
	        'uid' => $orderData['uid'],
	        'name' => $orderData['name'],
     	    'format' => $formatNum,//主要优化索引
     	    'dtype' => $orderData['dtype'],
	        'bs' => $actionType,
	        'kp' => 'close',
	        'trade_id' => $orderData['id'],
	        'times' => $times,
	        'num' => $orderData['num'],
	        'chi_price' => $posData['price'],
	        'price' => $orderData['price'],
	        'cj_price' => $cjPrice,
	        'commission' => $posData['commission'],
	        'overnight' => $posData['overnight'],
	        'additional' => $posData['additional'],
	        'yk' => $yk,
			'ykl' => $ykl,
	        'source' => $source,
	        'date' => $datetime,
	    );
	    $table = 'cfd_cfd_trade_log';
	    if (!$this->db->insert($table, $log_arr)) throw new Exception('L:'.__LINE__.' 添加交易记录失败', 1);
		// 返回用户ID
		return $posData['uid'];
	}


	// 判断是否在波动范围
	private function checkFloatingRange($orderData, $actionType, $new_com, $datetime) {
		// 检查佣金指数 是否在波动范围内
		$denomConfig = $this->cfdclass->getDenomConfig();
		$floating_rang = $denomConfig['floating_rang'];
		if (!$floating_rang) throw new Exception('L:'.__LINE__.' 获取参数失败!', 1);
		$floating_rang = $floating_rang[$orderData['type']];
		$max = $floating_rang[$orderData['commission']]['max'];
		$rs  = false;
		// echo "new_com=".$new_com."\n";
		// echo "type=".$orderData['type']."\n";
		// var_dump($floating_rang);
		// echo "commission=".$orderData['commission']."\n";
		// echo "max=".$max."\n";
		if ($new_com > $max) {
			// 取消订单
			$uid = $orderData['uid'];
			$id = $orderData['id'];

			// 更新订单状态
			$table = "cfd_cfd_".$actionType;
			$where = array('id'=>$id,'status'=>1,'flag'=>0);
			$this->db->set('status', 4, FALSE);
			$this->db->set('flag', 1, FALSE);
			$this->db->where($where);
			if(!$this->db->update($table)) throw new Exception('L:'.__LINE__.' 更新订单状态失败!', 1);

			// 添加撤单记录
			$source  = $this->cfdConfig['doing'][$actionType]['overRange']['source'];
			$table   = 'cfd_cfd_trade_log';
			$log_arr = array(
				'uid' => $uid,
				'name' => $orderData['name'],
				'dtype' => $orderData['dtype'],
				'bs' => $actionType,
				'kp' => $orderData['kp'],
				'uid' => $uid,
				'times' => $orderData['times'],
				'num' => $orderData['num'],
				'price' => $orderData['price'],
				'cj_price' => 0,
				'commission' => 0,
				'overnight' => 0,
				'additional' => 0,
				'source' => $source,
				'date' => $datetime,
			);
			if (!$this->db->insert($table, $log_arr)) throw new Exception('L:'.__LINE__.' 添加撤单记录失败!', 1);

			// 退币到用户账户
			$where     = "uid='{$uid}'";
			$use_value = $this->cfdClass->countBZJ(bcsub($orderData['num'], $orderData['cjnum']), $orderData['times']);
			$data_arr  =  array(
				'uid' => $uid,
				'name' => $orderData['name'],
				'object' => $orderData['dtype'],
				'use_value' => $use_value,
				'source' => $source,
				'add_time' => $datetime
			);
			if (!$this->cfdClass->add($data_arr)) throw new Exception('L:'.__LINE__.' 撤单加失败!', 1);
		} else {
			$rs = true;
		}
		return $rs;
	}

	private function checkAbnormal($actionType='none') {
		$redisData = $this->cfdClass->redisAllData();
		try {
			$now = time();
			if($redisData['trade']['BID_PRICE']>=$redisData['trade']['ASK_PRICE']){
				throw new Exception('L:'.__LINE__.' 价格数据异常1!', 1);
			}
			switch($actionType){
				case 'bid'://买多
				case 'ask_ping'://平空
					if (
						bccomp('300', bcsub($now, $redisData['trade']['tmLastModify'])) != 1 ||
						$redisData['trade']['ASK_PRICE'] == '0' || 
						$redisData['trade']['BID_PRICE'] == $redisData['trade']['ASK_PRICE']
					) throw new Exception('L:'.__LINE__.' 数据异常2!', 1);
					var_dump(bccomp('300', bcsub($now, $redisData['trade']['tmLastModify'])) != 1);
					var_dump($redisData['trade']['ASK_PRICE'] == '0');
					var_dump($redisData['trade']['ASK_PRICE'] == '0');
					break;
				case 'ask'://卖空
				case 'bid_ping'://平多
					if (
						bccomp('300', bcsub($now, $redisData['trade']['tmLastModify'])) != 1 ||
						$redisData['trade']['BID_PRICE'] == '0' ||
						$redisData['trade']['BID_PRICE'] == $redisData['trade']['ASK_PRICE']
					) throw new Exception('L:'.__LINE__.' 数据异常3!', 1);
					break;
				default:
					if (
						bccomp('300', bcsub($now, $redisData['trade']['tmLastModify'])) != 1 ||
						$redisData['trade']['BID_PRICE'] == '0' || 
						$redisData['trade']['BID_PRICE'] >= $redisData['trade']['ASK_PRICE']
					) throw new Exception('L:'.__LINE__.' 数据异常4!', 1);
			}
			$rs = true;
		} catch (Exception $e) {
			$rs = false;
		}
		return $rs;
	}


		
}
